using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace newtelligence.DasBlog.Web.Core
{
	
	/// <summary>
	/// Summary description for ValidTagCollection.
	/// </summary>
    [XmlRoot("validTags", Namespace = "urn:newtelligence-com:dasblog:config")]
    [XmlType(Namespace = "urn:newtelligence-com:dasblog:config")]
    public class ValidTagCollection : ICollection
    {

		// required for xml serializer
        public ValidTagCollection()
        {
			// ...
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="ValidTagCollection"/> class.
		/// </summary>
		/// <param name="tagsDefinition">The tags definition, defined as 'tag1@att1@att2,tag2@att3@att4'.</param>
        public ValidTagCollection(string tagsDefinition)
        {
            if (tagsDefinition == null || tagsDefinition.Length == 0)
            {
				return;
			}

			this.tagsDefinition = tagsDefinition;

			string[] splitTags = tagsDefinition.Split(',');

            foreach (string tagDef in splitTags)
            {
                ValidTag tag = new ValidTag(tagDef);
                tags.Add(tag.Name, tag);
			}
		}


        public void Add(ValidTag tag)
        {

            if (tag == null)
            {
				throw new ArgumentNullException("tag");
			}

			tags.Add(tag.Name, tag);
		}
		
		/// <summary>
		/// Copies the ValidTags to the array, starting at the index.
		/// </summary>
		/// <param name="array">The array to copy the tags to.</param>
		/// <param name="index">The index to start at.</param>
        void ICollection.CopyTo(Array array, int index)
        {

            if (!(array is ValidTag[]))
            {
                throw new ArgumentException("Expected array of ValidTags", "array");
            }

            tags.Values.CopyTo((ValidTag[])array, index);
		}

		/// <summary>
		/// Gets the enumerator over the tags.
		/// </summary>
		/// <returns>The enumerator.</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {

			// implement a ValidTagEnumerator when we actually need one
			return tags.Values.GetEnumerator();
		}

		/// <summary>
		/// Determines if the tagName is valid.
		/// </summary>
		/// <param name="tagName">The tag to validate.</param>
		/// <returns><see langword="true" /> if the tagName is valid; otherwise, <see langword="false" />.</returns>
        public bool IsValidTag(string tagName)
        {
			return tags[tagName] != null && ((ValidTag)tags[tagName]).IsAllowed;
		}

		/// <summary>
		/// Gets the number of tags in the collection.
		/// </summary>
		/// <value>The number of tags in the collection.</value>
		[XmlIgnore]
        public int Count
        {
			[DebuggerStepThrough]
            get
            {
				return tags.Count;
			}									  
		}										  

		/// <summary>
		/// Gets the number of allowed tags.
		/// </summary>
		/// <value>The allowed tags count.</value>
		public int AllowedTagsCount
		{
			get
			{
                int count = 0;
                foreach (ValidTag tag in this)
				{
                    if (tag.IsAllowed)
					{
                        count++;
					}
				}
				return count;
			}
		}

		/// <summary>
		/// Gets a value
		/// indicating whether access to the <see cref="T:System.Collections.ICollection"/> is synchronized
		/// (thread-safe).
		/// </summary>
		/// <value>Always returns <see langword="false" />.</value>
		[XmlIgnore]
        bool ICollection.IsSynchronized
        {
			[DebuggerStepThrough]
            get
            {
				return false;
			}
		}

		/// <summary>
		/// Gets an object that
		/// can be used to synchronize access to the <see cref="T:System.Collections.ICollection"/>.
		/// </summary>
		/// <value>An object to synchronize access to the collection.</value>
		[XmlIgnore]
        object ICollection.SyncRoot
        {
			[DebuggerStepThrough]
            get
            {
				return ((ICollection)tags).SyncRoot;
			}
		}

		/// <summary>
		/// Returns a <see cref="T:System.String"/> that represents the current <see cref="ValidTag"/>.
		/// </summary>
		/// <returns>
		/// A <see cref="T:System.String"/> that represents the current <see cref="ValidTag"/>.
		/// </returns>
        public override string ToString()
        {

			StringBuilder sb = new StringBuilder();
			
            foreach (ValidTag tag in this)
            {
                if (tag.IsAllowed)
                {
                    sb.Append(tag.ToString() + ", ");
				}
			}

            if (sb.Length > 0)
            {
				// remove trailing ", "
				sb.Remove(sb.Length - 2, 2);
			}

			return sb.ToString();
		}

		public string ToJavaScriptArray() 
		{
			StringBuilder sb = new StringBuilder();
			
            foreach (ValidTag tag in this)
			{
                if (tag.IsAllowed)
				{
                    sb.Append("'" + tag.Name + "', ");
				}
			}

            if (sb.Length > 0)
			{
				// remove trailing ", "
				sb.Remove(sb.Length - 2, 2);
			}

			return sb.ToString();
		}

		/// <summary>
		/// Gets the tags definition.
		/// </summary>
		/// <value>The tags definition.</value>
		[XmlIgnore]
        public string TagsDefinition
        {
			[DebuggerStepThrough]
            get
            {
				return this.tagsDefinition;
			}
		}

		/// <summary>
		/// Gets the <see cref="ValidTag"/> with the specified tag name.
		/// </summary>
		/// <value>The <see cref="ValidTag"/>.</value>
        public ValidTag this[string tagName]
        {
            get
            {
				return (ValidTag)tags[tagName];
			}
		}

         /// <summary>
        /// Gets the <see cref="ValidTag"/> at the specified index.
        /// </summary>
        /// <value>The <see cref="ValidTag"/>.</value>
        public ValidTag this[int index]
        {
            get
            {
                string key = tags.Keys[index];
                return tags[key];
            }
            set
            {
                string key = tags.Keys[index];
                tags[key] = value;
            }
        }

		// for versioning
        [XmlAnyElement]
        public XmlElement[] AnyElements;
        [XmlAnyAttribute]
        public XmlAttribute[] AnyAttributes;

		// use invariant culture so case insensitive comparison 
		// behaves like we expect for tags
        private SortedList<string, ValidTag> tags = new SortedList<string, ValidTag>(StringComparer.InvariantCultureIgnoreCase);
		private string tagsDefinition;
	}
}
